package work.linruchang.util.bean.wrapper.impl;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import work.linruchang.util.EnhanceReflectUtil;
import work.linruchang.util.EnhanceStrUtil;
import work.linruchang.util.LambdaUtil;
import work.linruchang.util.bean.wrapper.BaseWrapper;
import work.linruchang.util.bean.wrapper.WhereWrapper;
import work.linruchang.util.bean.wrapper.db.SqlColumnInfo;
import work.linruchang.util.bean.wrapper.db.SqlFragment;
import work.linruchang.util.other.SFunction;

import java.util.*;

/**
 *
 *
 * @author LinRuChang
 * @version 1.0
 * @date 2022/01/17
 * @since 1.8
 **/
public class WhereWrapperImpl<MasterTable, T extends BaseWrapper> extends BaseWrapperImpl<MasterTable, Object> implements WhereWrapper<MasterTable, T> {

    /**
     * 表字段值必须有值
     *
     * @param dbFieldName 主表的字段
     * @return
     */
    @Override
    public T notEmptyFieldValue(String dbFieldName) {
        return notEmptyFieldValue(getFirstTableClazz(), dbFieldName);
    }

    @Override
    public T notEmptyFieldValue(Class tableClazz, String dbFieldName) {
        return notEmptyFieldValue(true, tableClazz, dbFieldName);
    }

    @Override
    public T notEmptyFieldValue(boolean condition, Class tableClazz, String dbFieldName) {
        return whereBuild(condition, tableClazz, dbFieldName, null, SqlFragment.WHERE_NOT_EMPTY_VALUE);
    }

    /**
     * 表字段值必须为空
     *
     * @param dbFieldName 主表的字段
     * @return
     */
    @Override
    public T emptyFieldValue(String dbFieldName) {
        return emptyFieldValue(getFirstTableClazz(), dbFieldName);
    }

    @Override
    public T emptyFieldValue(Class tableClazz, String dbFieldName) {
        return emptyFieldValue(true, tableClazz, dbFieldName);
    }

    @Override
    public T emptyFieldValue(boolean condition, Class tableClazz, String dbFieldName) {
        return whereBuild(condition, tableClazz, dbFieldName, null, SqlFragment.WHERE_EMPTY_VALUE);
    }

    @Override
    public T eq(SFunction<MasterTable,?> dbFieldName, Object value) {
        return eq(LambdaUtil.getTagetClazz(dbFieldName),LambdaUtil.getFieldName(dbFieldName),value);
    }


    /**
     * =
     *
     * @param dbFieldName 主表的字段
     * @param value       字段值
     * @return
     */
    @Override
    public T eq(String dbFieldName, Object value) {
        return eq(getFirstTableClazz(), dbFieldName, value);
    }

    @Override
    public T eq(Class tableClazz, String dbFieldName, Object value) {
        return eq(true, tableClazz, dbFieldName, value);
    }

    @Override
    public T eq(boolean condition, Class tableClazz, String dbFieldName, Object value) {
        return whereBuild(condition, tableClazz, dbFieldName, value, SqlFragment.WHERE_EQ);
    }

    /**
     * =
     * 如果Value为空值则直接忽略此条件构建
     *
     * @param dbFieldName 主表的字段
     * @param value       字段值
     * @return
     */
    @Override
    public T eqIgnoreEmptyValue(String dbFieldName, Object value) {
        return eqIgnoreEmptyValue(getFirstTableClazz(), dbFieldName, value);
    }

    @Override
    public T eqIgnoreEmptyValue(Class tableClazz, String dbFieldName, Object value) {
        return eq(ObjectUtil.isNotEmpty(value), tableClazz, dbFieldName, value);
    }


    /**
     * <=
     *
     * @param dbFieldName
     * @param value
     * @return
     */
    @Override
    public T le(String dbFieldName, Object value) {
        return le(getFirstTableClazz(), dbFieldName, value);
    }

    @Override
    public T le(Class tableClazz, String dbFieldName, Object value) {
        return le(true, tableClazz, dbFieldName, value);
    }

    @Override
    public T le(boolean condition, Class tableClazz, String dbFieldName, Object value) {
        return whereBuild(condition, tableClazz, dbFieldName, value, SqlFragment.WHERE_LE);
    }

    /**
     * <=
     * 如果Value为空值则直接忽略此条件构建
     *
     * @param dbFieldName 主表的字段
     * @param value       字段值
     * @return
     */
    @Override
    public T leIgnoreEmptyValue(String dbFieldName, Object value) {
        return leIgnoreEmptyValue(getFirstTableClazz(), dbFieldName, value);
    }

    @Override
    public T leIgnoreEmptyValue(Class tableClazz, String dbFieldName, Object value) {
        return le(ObjectUtil.isNotEmpty(value), tableClazz, dbFieldName, value);
    }


    /**
     * >=
     *
     * @param dbFieldName
     * @param value
     * @return
     */
    @Override
    public T ge(String dbFieldName, Object value) {
        return ge(getFirstTableClazz(), dbFieldName, value);
    }

    @Override
    public T ge(Class tableClazz, String dbFieldName, Object value) {
        return ge(true, tableClazz, dbFieldName, value);
    }

    @Override
    public T ge(boolean condition, Class tableClazz, String dbFieldName, Object value) {
        return whereBuild(condition, tableClazz, dbFieldName, value, SqlFragment.WHERE_GE);
    }

    /**
     * >=
     * 如果Value为空值则直接忽略此条件构建
     *
     * @param dbFieldName 主表的字段
     * @param value       字段值
     * @return
     */
    @Override
    public T geIgnoreEmptyValue(String dbFieldName, Object value) {
        return geIgnoreEmptyValue(getFirstTableClazz(), dbFieldName, value);
    }

    @Override
    public T geIgnoreEmptyValue(Class tableClazz, String dbFieldName, Object value) {
        return ge(ObjectUtil.isNotEmpty(value), tableClazz, dbFieldName, value);
    }


    /**
     * <
     *
     * @param dbFieldName
     * @param value
     * @return
     */
    @Override
    public T lt(String dbFieldName, Object value) {
        return lt(getFirstTableClazz(), dbFieldName, value);
    }

    @Override
    public T lt(Class tableClazz, String dbFieldName, Object value) {
        return lt(true, tableClazz, dbFieldName, value);
    }

    @Override
    public T lt(boolean condition, Class tableClazz, String dbFieldName, Object value) {
        return whereBuild(condition, tableClazz, dbFieldName, value, SqlFragment.WHERE_LT);
    }


    /**
     * <
     * 如果Value为空值则直接忽略此条件构建
     *
     * @param dbFieldName 主表的字段
     * @param value       字段值
     * @return
     */
    @Override
    public T ltIgnoreEmptyValue(String dbFieldName, Object value) {
        return ltIgnoreEmptyValue(getFirstTableClazz(), dbFieldName, value);
    }

    @Override
    public T ltIgnoreEmptyValue(Class tableClazz, String dbFieldName, Object value) {
        return lt(ObjectUtil.isNotEmpty(value), tableClazz, dbFieldName, value);
    }


    /**
     * >
     *
     * @param dbFieldName
     * @param value
     * @return
     */
    @Override
    public T gt(String dbFieldName, Object value) {
        return gt(getFirstTableClazz(), dbFieldName, value);
    }

    @Override
    public T gt(Class tableClazz, String dbFieldName, Object value) {
        return gt(true, tableClazz, dbFieldName, value);
    }

    @Override
    public T gt(boolean condition, Class tableClazz, String dbFieldName, Object value) {
        return whereBuild(condition, tableClazz, dbFieldName, value, SqlFragment.WHERE_GT);
    }

    /**
     * >
     * 如果Value为空值则直接忽略此条件构建
     *
     * @param dbFieldName 主表的字段
     * @param value       字段值
     * @return
     */
    @Override
    public T gtIgnoreEmptyValue(String dbFieldName, Object value) {
        return gtIgnoreEmptyValue(getFirstTableClazz(), dbFieldName, value);
    }

    @Override
    public T gtIgnoreEmptyValue(Class tableClazz, String dbFieldName, Object value) {
        return gt(ObjectUtil.isNotEmpty(value), tableClazz, dbFieldName, value);
    }


    /**
     * in
     *
     * @param dbFieldName
     * @param value
     * @return
     */
    @Override
    public T in(String dbFieldName, Object value) {
        return in(getFirstTableClazz(), dbFieldName, value);
    }

    @Override
    public T in(Class tableClazz, String dbFieldName, Object value) {
        return in(true, tableClazz, dbFieldName, value);
    }

    @Override
    public T in(boolean condition, Class tableClazz, String dbFieldName, Object value) {
        return whereBuild(condition, tableClazz, dbFieldName, value, SqlFragment.WHERE_IN);
    }


    /**
     * in
     * 如果Value为空值则直接忽略此条件构建
     *
     * @param dbFieldName 主表的字段
     * @param value       字段值
     * @return
     */
    @Override
    public T inIgnoreEmptyValue(String dbFieldName, Object value) {
        return inIgnoreEmptyValue(getFirstTableClazz(), dbFieldName, value);
    }

    @Override
    public T inIgnoreEmptyValue(Class tableClazz, String dbFieldName, Object value) {
        return in(ObjectUtil.isNotEmpty(value), tableClazz, dbFieldName, value);
    }


    /**
     * not In
     *
     * @param dbFieldName
     * @param value
     * @return
     */
    @Override
    public T notIn(String dbFieldName, Object value) {
        return notIn(getFirstTableClazz(), dbFieldName, value);
    }

    @Override
    public T notIn(Class tableClazz, String dbFieldName, Object value) {
        return notIn(true, tableClazz, dbFieldName, value);
    }

    @Override
    public T notIn(boolean condition, Class tableClazz, String dbFieldName, Object value) {
        return whereBuild(condition, tableClazz, dbFieldName, value, SqlFragment.WHERE_NOT_IN);
    }


    /**
     * not In
     * 如果Value为空值则直接忽略此条件构建
     *
     * @param dbFieldName 主表的字段
     * @param value       字段值
     * @return
     */
    @Override
    public T notInIgnoreEmptyValue(String dbFieldName, Object value) {
        return notInIgnoreEmptyValue(getFirstTableClazz(), dbFieldName, value);
    }

    @Override
    public T notInIgnoreEmptyValue(Class tableClazz, String dbFieldName, Object value) {
        return notIn(ObjectUtil.isNotEmpty(value), tableClazz, dbFieldName, value);
    }


    /**
     * BETWEEN ? AND ?
     *
     * @param dbFieldName
     * @param value1
     * @param value2
     * @return
     */
    @Override
    public T betweenAnd(String dbFieldName, Object value1, Object value2) {
        return betweenAnd(getFirstTableClazz(), dbFieldName, value1, value2);
    }

    @Override
    public T betweenAnd(Class tableClazz, String dbFieldName, Object value1, Object value2) {
        return betweenAnd(true, tableClazz, dbFieldName, value1, value2);
    }

    @Override
    public T betweenAnd(boolean condition, Class tableClazz, String dbFieldName, Object value1, Object value2) {
        return whereBuild(condition, tableClazz, dbFieldName, value1, value2, SqlFragment.WHERE_BETWEEN_AND);
    }


    /**
     * not In
     * 如果Value为空值则直接忽略此条件构建
     *
     * @param dbFieldName 主表的字段
     * @param value       字段值1
     * @param value       字段值2
     * @return
     */
    @Override
    public T betweenAndIgnoreEmptyValue(String dbFieldName, Object value, Object value2) {
        return betweenAndIgnoreEmptyValue(getFirstTableClazz(), dbFieldName, value, value2);
    }

    @Override
    public T betweenAndIgnoreEmptyValue(Class tableClazz, String dbFieldName, Object value, Object value2) {
        return betweenAnd(ObjectUtil.isAllNotEmpty(value, value2), tableClazz, dbFieldName, value, value2);
    }


    /**
     * like '%值%'
     *
     * @param dbFieldName
     * @param value1
     * @return
     */
    @Override
    public T like(String dbFieldName, Object value1) {
        return like(getFirstTableClazz(), dbFieldName, value1);
    }

    @Override
    public T like(Class tableClazz, String dbFieldName, Object value1) {
        String likeValue = "%" + value1 + "%";
        return like(true, tableClazz, dbFieldName, likeValue);
    }

    @Override
    public T like(boolean condition, Class tableClazz, String dbFieldName, Object value) {
        return whereBuild(condition, tableClazz, dbFieldName, value, SqlFragment.WHERE_LIKE);
    }


    /**
     * like '%值%'
     * 如果Value为空值则直接忽略此条件构建
     *
     * @param dbFieldName 主表的字段
     * @param value       字段值
     * @return
     */
    @Override
    public T likeIgnoreEmptyValue(String dbFieldName, Object value) {
        return likeIgnoreEmptyValue(getFirstTableClazz(), dbFieldName, value);
    }

    @Override
    public T likeIgnoreEmptyValue(Class tableClazz, String dbFieldName, Object value) {
        return like(ObjectUtil.isNotEmpty(value), tableClazz, dbFieldName, value);
    }


    /**
     * like '%值'
     *
     * @param dbFieldName
     * @param value1
     * @return
     */
    @Override
    public T likeLeft(String dbFieldName, Object value1) {
        return likeLeft(getFirstTableClazz(), dbFieldName, value1);
    }

    @Override
    public T likeLeft(Class tableClazz, String dbFieldName, Object value1) {
        String likeValue = "%" + value1;
        return likeLeft(true, tableClazz, dbFieldName, likeValue);
    }

    @Override
    public T likeLeft(boolean condition, Class tableClazz, String dbFieldName, Object value) {
        return whereBuild(condition, tableClazz, dbFieldName, value, SqlFragment.WHERE_LIKE);
    }

    /**
     * like '%值'
     * 如果Value为空值则直接忽略此条件构建
     *
     * @param dbFieldName 主表的字段
     * @param value       字段值
     * @return
     */
    @Override
    public T likeLeftIgnoreEmptyValue(String dbFieldName, Object value) {
        return likeLeftIgnoreEmptyValue(getFirstTableClazz(), dbFieldName, value);
    }

    @Override
    public T likeLeftIgnoreEmptyValue(Class tableClazz, String dbFieldName, Object value) {
        return likeLeft(ObjectUtil.isNotEmpty(value), tableClazz, dbFieldName, value);
    }


    /**
     * like '值%'
     *
     * @param dbFieldName
     * @param value1
     * @return
     */
    @Override
    public T likeRight(String dbFieldName, Object value1) {
        return likeRight(getFirstTableClazz(), dbFieldName, value1);
    }

    @Override
    public T likeRight(Class tableClazz, String dbFieldName, Object value1) {
        String likeValue = value1 + "%";
        return likeRight(true, tableClazz, dbFieldName, likeValue);
    }

    @Override
    public T likeRight(boolean condition, Class tableClazz, String dbFieldName, Object value) {
        return whereBuild(condition, tableClazz, dbFieldName, value, SqlFragment.WHERE_LIKE);
    }


    /**
     * like '值%'
     * 如果Value为空值则直接忽略此条件构建
     *
     * @param dbFieldName 主表的字段
     * @param value       字段值
     * @return
     */
    @Override
    public T likeRightIgnoreEmptyValue(String dbFieldName, Object value) {
        return likeRightIgnoreEmptyValue(getFirstTableClazz(), dbFieldName, value);
    }

    @Override
    public T likeRightIgnoreEmptyValue(Class tableClazz, String dbFieldName, Object value) {
        return likeRight(ObjectUtil.isNotEmpty(value), tableClazz, dbFieldName, value);
    }


    /**
     * 构建where
     *
     * @param condition   条件是否需要
     * @param tableClazz  目标表
     * @param dbFieldName 数据库字段
     * @param value1      字段值   == 大部分符号传值只传一个， === null则直接忽略此条件
     *                    遇到特殊的如{@link SqlFragment#WHERE_BETWEEN_AND}需要传value2参数
     * @param symbol      条件符号 {@link SqlFragment#WHERE_EQ}
     *                    空则默认是{@link SqlFragment#WHERE_EQ}
     * @return
     */
    private T whereBuild(boolean condition, Class tableClazz, String dbFieldName, Object value1, String symbol) {
        Assert.isFalse(StrUtil.equals(symbol, SqlFragment.WHERE_BETWEEN_AND), "此重载方法不支持{}片段的构建，由于没有指定参数2，请使用另一个重载方法构建", SqlFragment.WHERE_BETWEEN_AND);
        return whereBuild(condition, tableClazz, dbFieldName, value1, null, symbol);
    }

    /**
     * 当前的where条件是否需要字段值进行构建
     *
     * @param symbolTemplate 条件符号 {@link SqlFragment#WHERE_EQ}
     * @return
     */
    private boolean isNeedFieldValueBuild(String symbolTemplate) {
        if (StrUtil.equalsAny(symbolTemplate, SqlFragment.WHERE_EMPTY_VALUE, SqlFragment.WHERE_NOT_EMPTY_VALUE)) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 构建where == 注意需要区分是having里面的条件还是where里面的条件
     *
     * @param condition      条件是否需要
     * @param tableClazz     目标表
     * @param dbFieldName    数据库字段
     * @param value1         字段值   == 大部分符号传值只传一个， === null则直接忽略此条件
     *                       遇到特殊的如{@link SqlFragment#WHERE_BETWEEN_AND}需要传value2参数
     * @param value2         字段值
     * @param symbolTemplate 条件符号 {@link SqlFragment#WHERE_EQ}
     *                       空则默认是{@link SqlFragment#WHERE_EQ}
     * @return
     */
    private T whereBuild(boolean condition, Class tableClazz, String dbFieldName, Object value1, Object value2, String symbolTemplate) {
        if (condition == false) {
            return (T) this;
        }
        symbolTemplate = StrUtil.blankToDefault(symbolTemplate, SqlFragment.WHERE_EQ);
        String columnAddAlias = getColumnAddTableAlias(tableClazz, dbFieldName);
        List currentSqlParams = new ArrayList();


        List<String> sqlFragments = this instanceof HavingWrapperImpl ? havingWhereSqlFragments : whereSqlFragments;
        List<Object> sqlParams = this instanceof HavingWrapperImpl ? havingWhereSqlParams : whereSqlParams;
        List<Class> sqlParamsTypes = this instanceof HavingWrapperImpl ? havingWhereSqlParamsTypes : whereSqlParamsTypes;
        List<SqlColumnInfo> whereColumnInfos = this instanceof HavingWrapperImpl ? getOnColumnInfos() : getWhereColumnInfos();
        Class fieldClassType = EnhanceReflectUtil.getDBColumnNameClassType(tableClazz, dbFieldName);

        //字段名填充
        String whereSql = StrUtil.format(symbolTemplate, columnAddAlias);

        if (isNeedFieldValueBuild(symbolTemplate)) {  //条件需要字段值
            if (StrUtil.equals(symbolTemplate, SqlFragment.WHERE_BETWEEN_AND)) {
                currentSqlParams.addAll(Arrays.asList(value1, value2));
            } else if (StrUtil.equalsAnyIgnoreCase(symbolTemplate, SqlFragment.WHERE_IN, SqlFragment.WHERE_NOT_IN)) {
                currentSqlParams = Collections.emptyList();
                if (ArrayUtil.isArray(value1)) {
                    currentSqlParams = Arrays.asList(currentSqlParams);
                } else if (value1 instanceof Collection) {
                    currentSqlParams = new ArrayList((Collection) value1);
                } else {
                    currentSqlParams = Arrays.asList(value1);
                }
                whereSql = StrUtil.format(whereSql, EnhanceStrUtil.questionMarkStr(currentSqlParams.size()));
            } else {
                currentSqlParams.add(value1);
            }

            for (int i = 0; i < currentSqlParams.size(); i++) {
                sqlParamsTypes.add(StrUtil.containsAnyIgnoreCase(symbolTemplate, "LIKE") ? String.class : fieldClassType);
            }
        }


        sqlParams.addAll(currentSqlParams);
        sqlFragments.add(whereSql);
        whereColumnInfos.add(new SqlColumnInfo(getTableInfo(tableClazz), EnhanceReflectUtil.getDBColumnName(tableClazz, dbFieldName), fieldClassType, null, currentSqlParams, this instanceof HavingWrapperImpl ? SqlColumnInfo.SQL_TYPE_ON : SqlColumnInfo.SQL_TYPE_WHERE));

        return this instanceof HavingWrapperImpl ? (T) ((HavingWrapperImpl) this).getBaseWrapper() : (T) this;
    }


}
